/**
 * 1、泛型方法
 */
function printArr<T>(arr: T[]): void {
  for (let item of arr) {
    console.log(item)
  }
}

printArr<number>([11, 22, 33])
printArr<string>(["aa", "dd", "ee"])

/**
 * 直接使用，利用ts的自动推断
 */
function echo<T>(arg: T): T {
  return arg
}

const result = echo(123)

/**
 * 同时指定多个泛型
 */
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}

const result2 = swap(["string", 123])

/**
 * 泛型数组
 */
function echoWithArray<T>(arg: T[]): T[] {
  return arg
}

const arr = echoWithArray([1, 2, 3])

/**
 * 对泛型的范围进行约束
 */
interface IWithLength {
  length: number
}

function echoWithLength<T extends IWithLength>(arg: T): T {
  console.log(arg.length);
  return arg
}

const arr1 = echoWithLength([1, 2, 3])
const str = echoWithLength("str")
const obj = echoWithLength({length: 10})


/**
 * 2、泛型类
 */
class ArrayList<T> {
  public list: T[] = []

  add(val: T): void {
    this.list.push(val)
  }
}

let numberList = new ArrayList<number>();
numberList.add(12)
numberList.add(23)
console.log(numberList.list)

/**
 * 泛型类
 */
class Queue<T> {
  private data = []

  push(item: T) {
    this.data.push(item)
  }

  pop(): T {
    return this.data.shift()
  }
}

const queue = new Queue<number>()

/**
 * 3、泛型接口
 */
interface IArrayList<T> {
  (x: T, y: T): T
}

let stringList: IArrayList<string> = function (x: string, y: string): string {
  return `${x}${y}`
}
console.log(stringList("1", "2"))

/**
 * 泛型接口
 */
interface Ikeypair<T, U> {
  key: T,
  value: U
}

let kp1: Ikeypair<string, number> = {key: "str", value: 1}
let kp2: Ikeypair<number, string> = {key: 2, value: "str"}